/**
 * Buzzer [ˈbʌzə(r)] n.蜂鸣器
 * 蜂鸣器是一种将电信号转换为声音信号的器件，常用来产生设备的按键音、报警音等提示信号
 * 蜂鸣器按驱动方式可分为"有源蜂鸣器"和"无源蜂鸣器"
 * 有源蜂鸣器：内部自带振荡源，将正负极接上直流电压即可持续发声，频率固定 (声音单一,不可改变)
 * 无源蜂鸣器：内部不带振荡源，需要控制器提供振荡脉冲才可发声，调整提供振荡脉冲的频率，可发出不同频率的声音 (扬声器,麦克风)
 * 
 * 驱动方式:
 *  1.三极管驱动
 *  2.集成电路驱动(ULN2003D, 达灵顿晶体管阵列,高电压,高电流,驱动器, 一般用于驱动"步进电机")
 * 
 * 视频有步进电机, 所以蜂鸣器顺便接在 ULN2003D 上的. (ULN2003D 大电压、电流,驱动步进电机)
 */
#include <REGX52.H>
#include "Delay_Utils.h"
#include "Timer0_Utils.h"

/**
 * TX-1C 是 P2_3, PNP三极管, 低电平响
 * 视频是 P1_5, 使用的是 ULN2003D 芯片驱动
 */
sbit BUZZER_DATA_PORT = P2^3;

//停止标志位, 和'Music_Note_and_Index.h'里定义的一样
#define MUSIC_END   0xFF

//16分音符的播放时长(125ms) = 四分音符的时长(500ms) / 4
#define MUSIC_16_DIATONIC_TIME    500/4

//C调: 音符&频率所对应的初值 对照表(11.0592MHz, 12T)
code unsigned int Music_Note_and_Frequency_Value_Table[] = {
    //休止符P(无声)
    0,
    //低音(小字组)
    63777, 63872, 63969, 64054, 64140, 64216, 64291, 64360, 64426, 64489, 64547, 64603,
    //中音(小字1组)
    64655, 64704, 64751, 64795, 64837, 64876, 64913, 64948, 64981, 65012, 65042, 65070,
    //高音(小字2组)
    65095, 65120, 65144, 65166, 65186, 65206, 65225, 65242, 65259, 65274, 65289, 65303
};

/**
 * 开始播放
 */
void Buzzer_ring() {
    BUZZER_DATA_PORT = 0;
}

/**
 * 停止播放
 */
void Buzzer_stop() {
    BUZZER_DATA_PORT = 1;
}

/**
 * 切换播放状态
 */
void Buzzer_switch() {
    BUZZER_DATA_PORT = !BUZZER_DATA_PORT;
}

/**
 * 滴滴响. bell n. 铃, 钟
 * @param ringMs 响铃多长时间, 单位ms
 */
void Buzzer_bell(unsigned int ringMs) {
    Buzzer_ring();
    Delayms(ringMs);
    Buzzer_stop();
}



//频率的索引
static unsigned char TH0_TL0_Value_Index;
static void Timer0_onTick() {
    //频率所对应的初值
    static unsigned int TH0_TL0_Value;
    TH0_TL0_Value = Music_Note_and_Frequency_Value_Table[TH0_TL0_Value_Index];
    //如果不是休止符P
    if(TH0_TL0_Value) {
        /*取对应频率值的重装载值到定时器*/
        //设置定时初值
        Timer0_set_TH_TL_Value(TH0_TL0_Value);
        //翻转蜂鸣器IO口
        Buzzer_switch();
    } else {
        //否则停止播放?
        Buzzer_stop();
    }
}

/**
 * 如果要播放音乐, 需要初始化
 * 你也可以不调用这个函数, 自己初始化
*/
void Buzzer_Play_Music_Init() {
    TH0_TL0_Value_Index = 0;
    Timer0_Init(1000, 0);
    //传入函数指针
    Timer0_setOnTickListener_Exact(0, &Timer0_onTick);
}

/**
 * 播放音乐
 * @param Music 音乐
 */
void Buzzer_Play_Music(unsigned char Music[]) {
    //乐谱位置
    unsigned int pos = 0;
    while (1) {
        //如果不是停止标志位
        if(Music[pos] != MUSIC_END) {
            //选择音符"频率"对应的"索引Index"
            TH0_TL0_Value_Index = Music[pos];
            pos++;
            /**
             * 获取频率所对应的"时长"
             * MUSIC_16_DIATONIC_TIME             : 16分音符的播放时长(125ms)
             * MUSIC_16_DIATONIC_TIME * Music[pos]: 16分音符*4 = 4分音符的时长
             */
            Delayms(MUSIC_16_DIATONIC_TIME * Music[pos]);
            pos++;
            //音符间短暂停顿
            Buzzer_stop();
            Timer0_pause(5);
        } else {
            //如果是停止标志位
            Timer0_stop();
            //停止蜂鸣器
            Buzzer_stop();
            //归0
            TH0_TL0_Value_Index = 0;
            //跳出while
            break;
        }
    }
}